Micron Document
C.S.Burner πŸͺ™ ━►πŸ”₯GIT Node

Node / reticulum_mirror / MeshChatX / files / docs / en / rns-link-api.md

Displaying Rendered β€’ View raw β€’ Download

docs/en/rns-link-api.md dev (54b0734e) Text, 7.04 KB

RNS Link API

MeshChatX exposes a generic Reticulum Link transport on the main WebSocket (T383838/ws). External apps and plugins can open links, run request/response exchanges, send packets, and tear links down without going through NomadNet helpers.

When to use it

T282828
Your app or plugin needs a live RNS Link
|
--> Not NomadNet page browsing
--> Not LXMF messaging
|
--> Use rns.link.* over /ws
or plugin managers rnsLink.*

Address peers by destination hash and aspect. Do not invent IP or hostname shortcuts.

Auth

When password auth is enabled, every T383838rns.link.* client message needs an authenticated session. Same rule as other WebSocket mutators.

Link lifecycle

T282828
Client sends rns.link.open
|
--> MeshChatX finds or opens path to destination
|
--> Link cached under (aspect, destination_hash)
|
--> Optional auto_identify
|
--> success / failure reply on same type + request_id
|
+--> rns.link.request / rns.link.send on the cached link
|
+--> rns.link.close tears down and uncaches
|
+--> disconnect cancels in-flight open / request for that client

Cache notes:

β€’ Key is T383838(aspect, destination_hash)
β€’ Cap is 64 active links
β€’ Idle links expire after about 30 minutes
β€’ Repeated request failures recycle the cached link so the next call re-opens

Client to server

All messages need a unique T383838request_id so replies can be matched.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”
β”‚ `BT383838`Fdddtype`f`b β”‚ Required fields β”‚ Optional β”‚ Beh… β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€
β”‚ T383838rns.link.open β”‚ T383838destination_hash, T383838aspect, T383838request_id β”‚ T383838auto_identify β”‚ Ope… β”‚
β”‚ T383838rns.link.identify β”‚ T383838destination_hash, T383838aspect, T383838request_id β”‚ β”‚ Cal… β”‚
β”‚ T383838rns.link.request β”‚ T383838destination_hash, T383838aspect, T383838path, T383838request_id β”‚ T383838data_b64, T383838timeout β”‚ Ens… β”‚
β”‚ T383838rns.link.send β”‚ T383838destination_hash, T383838aspect, T383838payload_b64, T383838request_id β”‚ β”‚ Sen… β”‚
β”‚ T383838rns.link.close β”‚ T383838destination_hash, T383838aspect, T383838request_id β”‚ β”‚ Tea… β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”˜

Field details:

β€’ T383838destination_hash: hex string of the peer destination
β€’ T383838aspect: dot-separated RNS app name + sub-aspects, for example T383838microrn.mgmt
β€’ T383838data_b64 / T383838payload_b64 / reply T383838body_b64: msgpack payloads, base64-encoded
β€’ T383838path: request path string on the remote link endpoint
β€’ T383838timeout: seconds for the request wait

Example open:

T282828
Tb4b4b4{
Tff7b72"type"Tb4b4b4: Ta5d6ff"rns.link.open"Tb4b4b4,
Tff7b72"destination_hash"Tb4b4b4: Ta5d6ff"aabbccddeeff00112233445566778899aabbccdd"Tb4b4b4,
Tff7b72"aspect"Tb4b4b4: Ta5d6ff"microrn.mgmt"Tb4b4b4,
Tff7b72"request_id"Tb4b4b4: Ta5d6ff"req-1"Tb4b4b4,
Tff7b72"auto_identify"Tb4b4b4: Tff7b72true
Tb4b4b4}


Example request:

T282828
Tb4b4b4{
Tff7b72"type"Tb4b4b4: Ta5d6ff"rns.link.request"Tb4b4b4,
Tff7b72"destination_hash"Tb4b4b4: Ta5d6ff"aabbccddeeff00112233445566778899aabbccdd"Tb4b4b4,
Tff7b72"aspect"Tb4b4b4: Ta5d6ff"microrn.mgmt"Tb4b4b4,
Tff7b72"path"Tb4b4b4: Ta5d6ff"/status"Tb4b4b4,
Tff7b72"request_id"Tb4b4b4: Ta5d6ff"req-2"Tb4b4b4,
Tff7b72"data_b64"Tb4b4b4: Tff7b72nullTb4b4b4,
Tff7b72"timeout"Tb4b4b4: T79c0ff15
Tb4b4b4}


Server to client

Per-T383838request_id replies reuse the same T383838type with a T383838status:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ `BT383838`Fdddstatus`f`b β”‚ Meaning β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ T383838phase β”‚ Progress step while opening or requesting β”‚
β”‚ T383838progress β”‚ Additional progress detail when available β”‚
β”‚ T383838success β”‚ Operation finished β”‚
β”‚ T383838failure β”‚ Operation failed (includes an error message) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Broadcast events (not tied to one T383838request_id):

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ `BT383838`Fdddtype`f`b β”‚ `BT383838`Fdddevent`f`b β”‚ Notes β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ T383838rns.link.event β”‚ T383838packet_received β”‚ Includes T383838payload_b64 β”‚
β”‚ T383838rns.link.event β”‚ T383838link_closed β”‚ Cached link removed β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

T282828
Inbound packet on a cached link
|
--> Broadcast rns.link.event / packet_received
|
Link torn down or evicted
|
--> Broadcast rns.link.event / link_closed

Plugins

Plugins call the same transport through HTTP invoke instead of speaking WebSocket types directly.

T282828
Plugin Worker
|
--> POST /api/v1/plugins/{id}/invoke
method: "callManager"
|
--> PluginManager checks granted managers
|
--> RnsLinkManager open / identify / request / send / close

Declare managers in T383838plugin.json:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Manager β”‚ Maps to β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ T383838rnsLink.open β”‚ Open or reuse link β”‚
β”‚ T383838rnsLink.identify β”‚ Identify on cached link β”‚
β”‚ T383838rnsLink.request β”‚ Request/response β”‚
β”‚ T383838rnsLink.send β”‚ Raw packet send β”‚
β”‚ T383838rnsLink.close β”‚ Teardown β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Subscribe to async traffic with:

T282828
Tb4b4b4{
Tff7b72"permissions"Tb4b4b4: Tb4b4b4{
Tff7b72"hooks"Tb4b4b4: Tb4b4b4[Ta5d6ff"rns.link.event"Tb4b4b4],
Tff7b72"managers"Tb4b4b4: Tb4b4b4[Ta5d6ff"rnsLink.open"Tb4b4b4, Ta5d6ff"rnsLink.identify"Tb4b4b4, Ta5d6ff"rnsLink.request"Tb4b4b4, Ta5d6ff"rnsLink.send"Tb4b4b4, Ta5d6ff"rnsLink.close"Tb4b4b4],
Tff7b72"storage"Tb4b4b4: Ta5d6ff"isolated"Tb4b4b4,
Tff7b72"network"Tb4b4b4: Ta5d6ff"none"
Tb4b4b4}
Tb4b4b4}


Hook delivery:

T282828
RnsLinkManager event
|
--> PluginManager.dispatch_hook("rns.link.event", …)
|
--> WebSocket plugin.event to the UI
|
--> Plugin Worker on_hook / event handler

External app pattern

T282828
Connect to MeshChatX /ws (auth cookie / session as required)
|
--> Send rns.link.open with request_id
|
--> Wait for matching success
|
--> Send rns.link.request or rns.link.send
|
--> Listen for rns.link.event broadcasts
|
--> Send rns.link.close when finished

Keep one T383838request_id per outstanding call. Cancel or ignore replies after you disconnect. MeshChatX cancels in-flight open/request work for that WebSocket client on disconnect.

Limits and failure behaviour

β€’ Missing path or unreachable peer returns T383838failure on the open/request reply
β€’ After repeated request failures on one cached link, MeshChatX recycles that link
β€’ Idle unused links are swept after about 30 minutes
β€’ Over-cap eviction drops the oldest unused links first

Implementation map

T282828
/ws rns.link.*
|
--> meshchat.py WebSocket dispatch + per-client task tracking
|
--> rns_link_manager.py cache, open, identify, request, send, close
|
--> plugin_manager.py capability wrappers + hook fan-out

See also

β€’ Plugins for install, grants, and invoke flow
β€’ Architecture and design for WebSocket and plugin runtime overview
β€’ Identities, privacy, and security for auth and session rules

Served by rngit 1.3.7 - Generated in 0.02s